
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// #include <libusb/libusb.h>
#include "SeaoryPrinter.h"

//=============================================================================
#define MAKEWORD(a, b)	  ((uint16_t)(((uint8_t)(a)) | ((uint16_t)((uint8_t)(b))) << 8))
#define MAKELONG(a, b)	  ((uint32_t)(((uint16_t)(a)) | ((uint32_t)((uint16_t)(b))) << 16))


typedef struct tagRGBQUAD
{
	uint8_t			rgbBlue;
	uint8_t			rgbGreen;
	uint8_t			rgbRed;
	uint8_t			rgbReserved;
} RGBQUAD;

typedef struct tagBITMAPFILEHEADER
{
	uint16_t		bfType;
	uint32_t		bfSize;
	uint16_t		bfReserved1;
	uint16_t		bfReserved2;
	uint32_t		bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER
{
	uint32_t		biSize;
	int32_t			biWidth;
	int32_t			biHeight;
	uint16_t		biPlanes;
	uint16_t		biBitCount;
	uint32_t		biCompression;
	uint32_t		biSizeImage;
	int32_t			biXPelsPerMeter;
	int32_t			biYPelsPerMeter;
	uint32_t		biClrUsed;
	uint32_t		biClrImportant;
} BITMAPINFOHEADER;


uint32_t  ReadBmpFile(char* szFileName, BITMAP* lpBmp)
{
	BITMAPFILEHEADER	BmpFileHdr = {0};
	BITMAPINFOHEADER	BmpInfoHdr = {0};
	RGBQUAD				IndexColors[256] = {{0}};
	uint32_t			dwRead = 0;
	bool				bRet = true;
	int32_t				nChannel = 3,
						nBitCount = 0,
						nRet = 0;

	uint32_t			dwReadOneTime = 0,
						dwTotal = 0;
	uint8_t				*lpTmp = 0,
						*lpTop = 0,
						*lpBottom = 0;
	uint32_t			i = 0;
	uint32_t			nHeight = 0;
	uint8_t				byValue = 0;

	FILE				*fp = 0;
	uint8_t				lpBuf[64] = {0};

	(void)bRet;

	if ( szFileName == 0 || lpBmp == 0 )
		return 87;//ERROR_INVALID_PARAMETER;

	if ( szFileName[0] == 0 )
		return 87;//ERROR_INVALID_PARAMETER;

	fp = fopen(szFileName, "rb");

	if ( fp == 0 )
		return 110;//ERROR_OPEN_FAILED

	nRet = fseek(fp, 0, SEEK_SET);

	//dwRead = fread((void*)&BmpFileHdr, 1, sizeof(BITMAPFILEHEADER), fp);
	dwRead = fread(lpBuf, 1, 14, fp);
	BmpFileHdr.bfType		= MAKEWORD(lpBuf[0], lpBuf[1]);
	BmpFileHdr.bfSize		= MAKELONG(MAKEWORD(lpBuf[2], lpBuf[3]), MAKEWORD(lpBuf[4], lpBuf[5]));
	BmpFileHdr.bfReserved1	= MAKEWORD(lpBuf[6], lpBuf[7]);
	BmpFileHdr.bfReserved1	= MAKEWORD(lpBuf[8], lpBuf[9]);
	BmpFileHdr.bfOffBits	= MAKELONG(MAKEWORD(lpBuf[10], lpBuf[11]), MAKEWORD(lpBuf[12], lpBuf[13]));

	dwRead = fread((void*)&BmpInfoHdr, 1, sizeof(BITMAPINFOHEADER), fp);

	nBitCount = BmpInfoHdr.biPlanes * BmpInfoHdr.biBitCount;
	if ( nBitCount != 8 && nBitCount != 24 )
	{
		nRet = fclose(fp);
		return 50;//=ERROR_NOT_SUPPORTED;
	}

	if ( nBitCount == 8 )
		dwRead = fread((void*)IndexColors, 1, sizeof(RGBQUAD)*256, fp);

	nChannel = BmpInfoHdr.biBitCount / 8;

	lpBmp->bmType		= 0;
	lpBmp->bmWidth		= BmpInfoHdr.biWidth;
	lpBmp->bmHeight		= BmpInfoHdr.biHeight;
	lpBmp->bmWidthBytes	= ((BmpInfoHdr.biWidth*nChannel+3)/4*4);
	lpBmp->bmPlanes		= BmpInfoHdr.biPlanes;
	lpBmp->bmBitsPixel	= BmpInfoHdr.biBitCount;

	dwTotal = lpBmp->bmWidthBytes * lpBmp->bmHeight;
	lpBmp->bmBits		= (void*)new char[dwTotal];

	nRet = fseek(fp, BmpFileHdr.bfOffBits, SEEK_SET);

	dwReadOneTime = 1 * 1024 * 1024;
	lpTmp = (uint8_t*)lpBmp->bmBits;

	while ( dwTotal > 0 )
	{
		if ( dwTotal >= dwReadOneTime )
		{
			dwRead = fread((void*)lpTmp, 1, dwReadOneTime, fp);

			dwTotal -= dwReadOneTime;
			lpTmp += dwReadOneTime;
		}
		else
		{
			dwRead = fread((void*)lpTmp, 1, dwTotal, fp);
			dwTotal = 0;
		}
	}

	fclose(fp);

	if ( nBitCount == 8 )
	{
		dwTotal = lpBmp->bmWidthBytes * lpBmp->bmHeight;
		lpTmp = (uint8_t*)lpBmp->bmBits;
		for(i=0;i<dwTotal;i++,lpTmp++)
		{
			byValue = *lpTmp;
			*lpTmp = IndexColors[byValue].rgbBlue;
		}
	}


	dwTotal = (uint32_t)lpBmp->bmWidthBytes;
	nHeight = lpBmp->bmHeight / 2;

	lpTmp = new uint8_t[dwTotal];
	lpTop = (uint8_t*)lpBmp->bmBits;
	lpBottom = (uint8_t*)lpBmp->bmBits + lpBmp->bmWidthBytes * (lpBmp->bmHeight-1);

	for(i=0;i<nHeight;i++)
	{
		memcpy(lpTmp, lpTop, dwTotal);
		memcpy(lpTop, lpBottom, dwTotal);
		memcpy(lpBottom, lpTmp, dwTotal);

		lpTop += dwTotal;
		lpBottom -= dwTotal;
	}

	delete [] lpTmp;

	return 0;
}

//=============================================================================
void GetErrorString(uint32_t dwErrorCode, char* szError)
{
	int32_t					i = 0;

	memset(szError, 0, 256);

	if ( dwErrorCode < 0x00010001 )
	{
		while ( ErrorMap2[i].dwErrCode != 0xFFFFFFFF )
		{
			if ( dwErrorCode == ErrorMap2[i].dwErrCode )
			{
				strcpy(szError, ErrorMap2[i].pDesc);
				break;
			}
			i++;
		}
		return;
	}

	while ( ErrorMap[i].dwErrCode != 0xFFFFFFFF )
	{
		if ( dwErrorCode == ErrorMap[i].dwErrCode )
		{
			strcpy(szError, ErrorMap[i].pDesc);
			break;
		}
		i++;
	}
}

//=============================================================================
uint32_t  TestEncodeMagTrackData(char *szPrinterPort, uint32_t dwMode)
{
	uint32_t			dwRet = 0;

	char				szT1[256] = {0}, szT2[256] = {0}, szT3[256] = {0};

	memset(szT1, 0, 256);
	memset(szT2, 0, 256);
	memset(szT3, 0, 256);
	strcpy(szT1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
	strcpy(szT2, "111222333444555666777888999000");
	strcpy(szT3, "123456789012345678901234567890");

	dwRet = SOY_PR_EncodeTrackA(szPrinterPort, dwMode, szT1, szT2, szT3, 1);
	printf("TestEncodeMagTrackData() return %d.\n", dwRet);

	return dwRet;
}

//=============================================================================
uint32_t  TestReadMagTrackData(char *szPrinterPort)
{
	uint32_t			dwRet = 0;

	char				szT1[256] = {0}, szT2[256] = {0}, szT3[256] = {0};

	memset(szT1, 0, 256);
	memset(szT2, 0, 256);
	memset(szT3, 0, 256);

	dwRet = SOY_PR_ReadTrackA(szPrinterPort, 0, szT1, szT2, szT3);
	printf("TestReadMagTrackData() return %d.\n", dwRet);
	printf("szT1 = \"%s\"\n", szT1);
	printf("szT2 = \"%s\"\n", szT2);
	printf("szT3 = \"%s\"\n", szT3);

	return dwRet;
}

//=============================================================================
uint32_t TestPrint(char* szPrinterPort, int32_t nPrintSide)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	uint32_t			dwSize = 0;
	uint8_t				*lpTmp = 0;

	uint32_t			dwStatus = 0;

	char				szBmpFile[256] = {0};

	PRINT_CARD_PARAM	JobPara = {0};

	BITMAP				Bmp24 = {0}, BmpK = {0}, BmpO = {0};
	BITMAP				Bmp24b = {0}, BmpKb = {0}, BmpOb = {0};

	int					nWidth = 1012, nHeight = 648;
	char				szModel[32] = {0};
	bool				bRxxx = false;
	
	(void)dwSize;
	(void)lpTmp;

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_GetPrinterInfoA() return = %d (%s)\n", dwRet, szError);
	if ( dwRet != 0 )
		return dwRet;

	if ( strcmp(szModel, "R600") == 0 || strcmp(szModel, "R600M") == 0 || strcmp(szModel, "DCE905") == 0 || strcmp(szModel, "DR600") == 0 || strcmp(szModel, "D600") == 0 )
	{
		nWidth = 2060; nHeight = 1296;
		bRxxx = true;
	}
	else if ( strcmp(szModel, "R300") == 0 )
	{
		nWidth = 1030, nHeight = 648;
		bRxxx = true;
	}

	memset(&Bmp24, 0, sizeof(BITMAP));
	memset(&BmpK, 0, sizeof(BITMAP));
	memset(&BmpO, 0, sizeof(BITMAP));
	memset(&Bmp24b, 0, sizeof(BITMAP));
	memset(&BmpKb, 0, sizeof(BITMAP));
	memset(&BmpOb, 0, sizeof(BITMAP));

	//front side --------------------------------
	if ( (nPrintSide & 0x01) == 0x01 )
	{
		sprintf(szBmpFile, "/data/cashway/%dx%d_bgr1.bmp", nWidth, nHeight);
		dwRet = ReadBmpFile(szBmpFile, &Bmp24);
		printf("ReadBmpFile(%s) return %d, bmWidth = %ld, bmHeight = %ld,\n", szBmpFile, dwRet, Bmp24.bmWidth, Bmp24.bmHeight);

		sprintf(szBmpFile, "/data/cashway/%dx%d_k1.bmp", nWidth, nHeight);
		dwRet = ReadBmpFile(szBmpFile, &BmpK);
		printf("ReadBmpFile(%s) return %d, bmWidth = %ld, bmHeight = %ld,\n", szBmpFile, dwRet, Bmp24.bmWidth, Bmp24.bmHeight);

		if ( !bRxxx )
		{
		sprintf(szBmpFile, "/data/cashway/%dx%d_o1.bmp", nWidth, nHeight);
		dwRet = ReadBmpFile(szBmpFile, &BmpO);
		printf("ReadBmpFile(%s) return %d, bmWidth = %ld, bmHeight = %ld,\n", szBmpFile, dwRet, Bmp24.bmWidth, Bmp24.bmHeight);
		}
	}

	//back side ---------------------------------
	if ( (nPrintSide & 0x02) == 0x02 )
	{
		sprintf(szBmpFile, "/data/cashway/%dx%d_bgr2.bmp", nWidth, nHeight);
		dwRet = ReadBmpFile(szBmpFile, &Bmp24b);
		printf("ReadBmpFile(%s) return %d, bmWidth = %ld, bmHeight = %ld,\n", szBmpFile, dwRet, Bmp24.bmWidth, Bmp24.bmHeight);

		sprintf(szBmpFile, "/data/cashway/%dx%d_k2.bmp", nWidth, nHeight);
		dwRet = ReadBmpFile(szBmpFile, &BmpKb);
		printf("ReadBmpFile(%s) return %d, bmWidth = %ld, bmHeight = %ld,\n", szBmpFile, dwRet, Bmp24.bmWidth, Bmp24.bmHeight);

		if ( !bRxxx )
		{
		sprintf(szBmpFile, "/data/cashway/%dx%d_o2.bmp", nWidth, nHeight);
		dwRet = ReadBmpFile(szBmpFile, &BmpOb);
		printf("ReadBmpFile(%s) return %d, bmWidth = %ld, bmHeight = %ld,\n", szBmpFile, dwRet, Bmp24.bmWidth, Bmp24.bmHeight);
		}
	}

	//
	dwStatus = 170;//device is busy
	while ( dwStatus == 170 )
	{
		dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
		if ( dwRet != 0 )
			dwStatus = dwRet;

		if ( dwStatus == 170 )
			usleep(2000*1000);
	}

	if ( dwStatus != 0 )
		dwRet = dwStatus;

	if ( dwRet == 0 && dwStatus == 0 )
	{
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		memset(&JobPara, 0, sizeof(PRINT_CARD_PARAM));

		JobPara.dwSize = sizeof(PRINT_CARD_PARAM);

		//all the BITMAP has 648 pixels width and 1012 pixels height and 24-bits per pixels
		//if the data pointer is null, than the plane will not be printed.
		JobPara.lpFrontBGR		= &Bmp24;
		JobPara.lpFrontK		= &BmpK;
		JobPara.lpFrontO		= &BmpO;
		JobPara.lpBackBGR		= &Bmp24b;
		JobPara.lpBackK			= &BmpKb;
		JobPara.lpBackO			= &BmpOb;

		//Heating Energy adjustment, value range of following fields are -127 ~ 127
		//same as driver UI Heating Energy tab
		//for ribbon YMCKO
		JobPara.chFrontHeatYMC		= 0;
		JobPara.chFrontHeatK		= 0;
		JobPara.chFrontHeatO		= 0;

		JobPara.chBackHeatYMC		= 0;
		JobPara.chBackHeatK			= 0;
		JobPara.chBackHeatO			= 0;

		//for ribbon K
		JobPara.chFrontHeatResinK	= 0;
		JobPara.chBackHeatResinK	= 0;

		printf("Start printing.....\n");
		dwRet = SOY_PR_PrintOneCardA(szPrinterPort, &JobPara);
	}

	//release memory buffer
	if ( Bmp24.bmBits )
		delete [] (uint8_t*)Bmp24.bmBits;

	if ( BmpK.bmBits )
		delete [] (uint8_t*)BmpK.bmBits;

	if ( BmpO.bmBits )
		delete [] (uint8_t*)BmpO.bmBits;

	if ( Bmp24b.bmBits )
		delete [] (uint8_t*)Bmp24b.bmBits;

	if ( BmpKb.bmBits )
		delete [] (uint8_t*)BmpKb.bmBits;

	if ( BmpOb.bmBits )
		delete [] (uint8_t*)BmpOb.bmBits;

	return dwRet;
}

//S21 机器使用 RYMCK 色带打印单面人像（人像为灰阶打印）加黑色文字临时身份证卡片。
//打印内容： 在 A4 纸张上抓取 cr80 大小范围打印彩色灰阶人像加黑色文字
//发卡方式：进卡盒进卡，后出卡口出卡,出卡需带持卡功能（距离和时间设置都需要），超时回收卡片返回废卡盒。
//覆膜区域：满版覆膜（ 提供取消 r 再次覆膜选项）
uint32_t setS21(char* szPrinterPort)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S21") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}


	//
	uint32_t			dwConfigType = 0;
	int32_t				nValue1 = 0, nValue2 = 0;
	int32_t				nConfigValue = 0;
	int32_t				nInputBin = 0;//card feeder
	int32_t				nOutputBin = 0;//output hopper

	//进卡设置
	dwConfigType = CONFIG_INPUT_BIN;
	nConfigValue = nInputBin;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_BIN) return = %d (%s)\n", dwRet, szError);

	//出卡设置
	nValue1 = nOutputBin;
	nValue2 = 1;//1=打印完成后走到待取卡位置, 0=打印完成后直接出卡
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_OUTPUT_BIN_MODE;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_OUTPUT_BIN_MODE) return = %d (%s)\n", dwRet, szError);

	//进卡出卡绑定
	nValue1 = nInputBin;
	nValue2 = nOutputBin;
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_INPUT_OUTPUT_BINDING;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_OUTPUT_BINDING) return = %d (%s)\n", dwRet, szError);

	//待取卡设置
	uint8_t				byOutputBin = 2;//1=front end,2=back end
	uint8_t				byWaitPos = 30;//x1mm
	uint32_t			dwWaitTime = 30;//x0.5second

	dwRet = SOY_PR_SetStandbyParametersA(szPrinterPort, byOutputBin, byWaitPos, dwWaitTime);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetStandbyParametersA() return = %d (%s)\n", dwRet, szError);
	if ( dwRet != 0 )
	{
		return dwRet;
	}

	return dwRet;
}

uint32_t printS21(char* szPrinterPort)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	(void)szError;

	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S21") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}

	//打印
	TestPrint(szPrinterPort, 1);

	return dwRet;
}

//毫米转像素
#define MM_TO_PIXEL(x) (int32_t)(x/25.4*300.0)

//S22J 机器使用 1/2ymcKO-n 色带，批量读写非接触 CPU 卡并正面打印彩色人像，黑色文字以及签注信息，背面打印黑色二维码。
//卡片类型： cpu 卡
//发卡方式： 进卡盒进卡，后出卡口出卡，出卡需带持卡功能（距离和时间设置都需要） ， 废卡和超时回收卡片进废卡盒
//模板信息： 正面 黑体加粗八号 背面 黑色左上角二维码（暂无数据，在色带可打印范围内编辑测试即可，需提供 ymc 和 k 打印两种选择）
int setS22J(char* szPrinterPort)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S22J") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}


	//
	uint32_t			dwConfigType = 0;
	int32_t				nValue1 = 0, nValue2 = 0;
	int32_t				nConfigValue = 0;
	int32_t				nInputBin = 0;//card feeder
	int32_t				nOutputBin = 0;//output hopper

	//进卡设置
	dwConfigType = CONFIG_INPUT_BIN;
	nConfigValue = nInputBin;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_BIN) return = %d (%s)\n", dwRet, szError);

	//出卡设置
	nValue1 = nOutputBin;
	nValue2 = 1;//1=打印完成后走到待取卡位置, 0=打印完成后直接出卡
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_OUTPUT_BIN_MODE;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_OUTPUT_BIN_MODE) return = %d (%s)\n", dwRet, szError);

	//进卡出卡绑定
	nValue1 = nInputBin;
	nValue2 = nOutputBin;
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_INPUT_OUTPUT_BINDING;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_OUTPUT_BINDING) return = %d (%s)\n", dwRet, szError);

	//待取卡设置
	uint8_t				byOutputBin = 2;//1=front end,2=back end
	uint8_t				byWaitPos = 30;//x1mm
	uint32_t			dwWaitTime = 30;//x0.5second

	dwRet = SOY_PR_SetStandbyParametersA(szPrinterPort, byOutputBin, byWaitPos, dwWaitTime);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetStandbyParametersA() return = %d (%s)\n", dwRet, szError);
	if ( dwRet != 0 )
	{
		return dwRet;
	}

	return dwRet;
}

int printS22J(char* szPrinterPort)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	(void)szError;

	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S22J") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}

	//打印
	TestPrint(szPrinterPort, 1);

	return dwRet;
}

//S20R 机器为单张读写非接触 CPU 卡并再局部擦写签注信息。
//发卡方式： 前进卡口进卡出卡 ，读取失败卡片按照进卡方向出卡，出卡需带持卡功能（距离和时间设置都需要），超时回收卡片从后卡口排除。
int setS20R(char* szPrinterPort)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S20R") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}


	//
	uint32_t			dwConfigType = 0;
	int32_t				nValue1 = 0, nValue2 = 0;
	int32_t				nConfigValue = 0;
	int32_t				nInputBin = 1;//front end manual
	int32_t				nOutputBin = 1;//front end manual

	//进卡设置
	dwConfigType = CONFIG_INPUT_BIN;
	nConfigValue = nInputBin;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_BIN) return = %d (%s)\n", dwRet, szError);

	//出卡设置
	nValue1 = nOutputBin;
	nValue2 = 1;//1=打印完成后走到待取卡位置, 0=打印完成后直接出卡
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_OUTPUT_BIN_MODE;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_OUTPUT_BIN_MODE) return = %d (%s)\n", dwRet, szError);

	//进卡出卡绑定
	nValue1 = nInputBin;
	nValue2 = nOutputBin;
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_INPUT_OUTPUT_BINDING;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_OUTPUT_BINDING) return = %d (%s)\n", dwRet, szError);

	//待取卡设置
	uint8_t				byOutputBin = 1;//1=front end,2=back end
	uint8_t				byWaitPos = 30;//x1mm
	uint32_t			dwWaitTime = 30;//x0.5second

	dwRet = SOY_PR_SetStandbyParametersA(szPrinterPort, byOutputBin, byWaitPos, dwWaitTime);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetStandbyParametersA() return = %d (%s)\n", dwRet, szError);
	if ( dwRet != 0 )
	{
		return dwRet;
	}

	//废卡设置
	nConfigValue = 2;//back end manual

	dwConfigType = CONFIG_REJECT_BIN;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_REJECT_BIN) return = %d (%s)\n", dwRet, szError);

	return dwRet;
}

int printS20R(char* szPrinterPort)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	(void)szError;

	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S20R") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}

	//打印
	TestPrint(szPrinterPort, 1);

	return dwRet;
}

//=============================================================================
uint32_t SetCardInOut(char* szPrinterPort, int32_t nInputBin, bool bAutoFeedM, bool bAdfHookMode, bool bRetryHookMode, bool bCardOutSensor, int32_t nOutputBin, bool bWaitForRemoval, int32_t nRejectBin)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};

	uint32_t			dwConfigType = 0;

	uint32_t			nHookMode = 0;
	int					nCardOutSensor = 0;

	int					nValue1 = 0, nValue2 = 0;
	int					nConfigValue = 0;

	//进卡设置
	dwConfigType = CONFIG_INPUT_BIN;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nInputBin);
		printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_BIN, nConfigValue=%d) return = %d (%s)\n", nConfigValue, dwRet, szError);

	if ( nInputBin == 0 )//card feeder
	{
		//for S22/S22K/E30
		if ( bAdfHookMode )
			nHookMode = 1;
		if ( bRetryHookMode )
			nHookMode += 2;
		dwConfigType = CONFIG_ADF_HOOK_MODE;
		dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nHookMode);
		printf("SOY_PR_SetPrinterConfigA(CONFIG_ADF_HOOK_MODE, nHookMode=%d) return = %d (%s)\n", nHookMode, dwRet, szError);

		if ( bCardOutSensor )
			nCardOutSensor = 1;
		dwConfigType = CONFIG_CARD_OUT_SENSOR;
		dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nCardOutSensor);
		printf("SOY_PR_SetPrinterConfigA(CONFIG_CARD_OUT_SENSOR, nCardOutSensor=%d) return = %d (%s)\n", nCardOutSensor, dwRet, szError);
	}
	else if ( nInputBin == 1 )//front manual
	{
		//[前端] 侦测到卡片时立即自动进卡
		dwConfigType = CONFIG_MANUAL_FEED_FRONT;
		nConfigValue = (int)bAutoFeedM;
		dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
		printf("SOY_PR_SetPrinterConfigA(CONFIG_MANUAL_FEED_FRONT, nConfigValue=%d) return = %d (%s)\n", nConfigValue, dwRet, szError);
	}
	else if ( nInputBin == 2 )//back manual
	{
		//[后端] 侦测到卡片时立即自动进卡
		dwConfigType = CONFIG_MANUAL_FEED_BACK;
		nConfigValue = (int)bAutoFeedM;
		dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
		printf("SOY_PR_SetPrinterConfigA(CONFIG_MANUAL_FEED_BACK, nConfigValue=%d) return = %d (%s)\n", nConfigValue, dwRet, szError);
	}

	//出卡设置
	if ( nOutputBin < 3 )
	{
		nValue1 = nOutputBin;
		if ( bWaitForRemoval )
			nValue2 = 1;//1=打印完成后走到待取卡位置, 0=打印完成后直接出卡
		else
			nValue2 = 0;
		nConfigValue = (nValue1 << 16) + nValue2;

		dwConfigType = CONFIG_OUTPUT_BIN_MODE;
		dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
		printf("SOY_PR_SetPrinterConfigA(CONFIG_OUTPUT_BIN_MODE, nConfigValue=%d) return = %d (%s)\n", nConfigValue, dwRet, szError);
	}

	//进卡出卡绑定
	nValue1 = nInputBin;
	nValue2 = nOutputBin;
	nConfigValue = (nValue1 << 16) + nValue2;

	dwConfigType = CONFIG_INPUT_OUTPUT_BINDING;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_INPUT_OUTPUT_BINDING, nConfigValue=%d) return = %d (%s)\n", nConfigValue, dwRet, szError);

	//废卡设置
	nConfigValue = nRejectBin;
	dwConfigType = CONFIG_REJECT_BIN;
	dwRet = SOY_PR_SetPrinterConfigA(szPrinterPort, dwConfigType, nConfigValue);
	printf("SOY_PR_SetPrinterConfigA(CONFIG_REJECT_BIN, nConfigValue=%d) return = %d (%s)\n", nConfigValue, dwRet, szError);

	return dwRet;
}

//=============================================================================
uint32_t SetStandbyParam(char* szPrinterPort, uint8_t byOutputBin, uint8_t byWaitPos, uint32_t dwWaitTime)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};
	(void)szError;
	//待取卡设置
//	uint8_t				byOutputBin = 2;//1=front end,2=back end
//	uint8_t				byWaitPos = 30;//x1mm
//	uint32_t			dwWaitTime = 30;//x0.5second

	dwRet = SOY_PR_SetStandbyParametersA(szPrinterPort, byOutputBin, byWaitPos, dwWaitTime);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_SetStandbyParametersA(byOutputBin=%d, byWaitPos=%d, dwWaitTime=%d) return = %d (%s)\n", byOutputBin, byWaitPos, dwWaitTime, dwRet, szError);

	return dwRet;
}

//=============================================================================
int setS20(char* szPrinterPort, int nType)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};
	(void)szError;
	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S20") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}

	int32_t		nInputBin = 0;
	bool		bAutoFeedM = false;
	bool		bAdfHookMode = false, bRetryHookMode = false, bCardOutSensor = false;
	int32_t		nOutputBin = 0;
	bool		bWaitForRemoval = false;
	int32_t		nRejectBin = 0;

	uint8_t		byWaitPos = 0;
	uint32_t	dwWaitTime = 0;

	if ( nType == 1 )
	{
		nInputBin = 1;//前端手动进卡口
		bAutoFeedM = true;//侦测到卡片时立即自动进卡
		nOutputBin = 1;//前端手动进卡口
		bWaitForRemoval = true;//打印完成后走到待取卡位置
		dwRet = SetCardInOut(szPrinterPort, nInputBin, bAutoFeedM, bAdfHookMode, bRetryHookMode, bCardOutSensor, nOutputBin, bWaitForRemoval, nRejectBin);

		byWaitPos = 60;//x1mm
		dwWaitTime = 0;//x0.5second
		dwRet = SetStandbyParam(szPrinterPort, nOutputBin, byWaitPos, dwWaitTime);
	}
	else if ( nType == 2 )
	{
		nInputBin = 1;//前端手动进卡口
		bAutoFeedM = true;//侦测到卡片时立即自动进卡
		nOutputBin = 4;//不要排出卡片
		dwRet = SetCardInOut(szPrinterPort, nInputBin, bAutoFeedM, bAdfHookMode, bRetryHookMode, bCardOutSensor, nOutputBin, bWaitForRemoval, nRejectBin);
	}

	return dwRet;
}

//=============================================================================
uint32_t printS20(char* szPrinterPort, int nType)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};
	bool				bCancelJob = false;

	uint32_t			dwStatus = 0;

	char				szCardPos[32] = {0};
	int					nCardPos = 0;
	int					nCommand = 0;

	char				szRibbonType[32] = {0};
	char				szRibbonCount[32] = {0};
	int					nRibbonCount = 0;

	(void)bCancelJob;
	(void)nCommand;
	(void)szRibbonType;

	SOY_PR_SetLogLevel(1);

	//1. 获取打印机状态
	dwStatus = 170;//device is busy
	while ( dwStatus == 170 )
	{
		dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
		GetErrorString(dwStatus, szError);
		printf("SOY_PR_GetPrinterStatusA() return = %d, dwStatus = 0x%08X (%s)\n", dwRet, dwStatus, szError);
		if ( dwRet != 0 )
			dwStatus = dwRet;

		if ( dwStatus == 170 )
			usleep(500*1000);
	}

	//1.a 打印机未连接，流程结束
	if ( dwStatus == 1167 )//The device is not connected.
		return 1167;

	//1.b 打印机未就绪
	if ( dwStatus != 0 )
	{
		//判断打印机内是否有卡
		dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_CARD_POSITION, szCardPos);
		printf("SOY_PR_GetPrinterInfoA(INFO_CARD_POSITION) => %s\n", szCardPos);
		nCardPos = atoi(szCardPos);
		if ( nCardPos != 0 )//打印机内有卡，从前门将卡片排出
		{
			dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_MOVE_CARD_TO_FRONT);
			GetErrorString(dwRet, szError);
			printf("SOY_PR_ExecCommandA(CMD_MOVE_CARD_TO_FRONT) return = %d (%s)\n", dwRet, szError);
			//if ( dwRet != 0 )
			//	return dwRet;
		}

		//复位
		dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_RESET_PRINTER_HARD);
		GetErrorString(dwRet, szError);
		printf("SOY_PR_ExecCommandA(CMD_RESET_PRINTER_HARD) return = %d (%s)\n", dwRet, szError);
		if ( dwRet != 0 )
			return dwRet;

		dwStatus = 170;//device is busy
		while ( dwStatus == 170 )
		{
			dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
			GetErrorString(dwStatus, szError);
			printf("SOY_PR_GetPrinterStatusA() return = %d, dwStatus = 0x%08X (%s)\n", dwRet, dwStatus, szError);
			if ( dwRet != 0 )
				dwStatus = dwRet;

			if ( dwStatus == 170 )
				usleep(500*1000);
		}

		//打印机未就绪，流程结束
		dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
		GetErrorString(dwStatus, szError);
		printf("SOY_PR_GetPrinterStatusA() return = %d, dwStatus = 0x%08X (%s)\n", dwRet, dwStatus, szError);
		if ( dwRet != 0 )
			return dwRet;

		if ( dwStatus != 0 )
			return dwStatus;
	}

	//2. 判断色带是否足量
	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_RIBBON_COUNT, szRibbonCount);
	printf("SOY_PR_GetPrinterInfoA(INFO_RIBBON_COUNT) => %s\n", szRibbonCount);
	nRibbonCount = atoi(szRibbonCount);

	//2.a 色带不足量，流程结束
	if ( nRibbonCount < 1 )
		return 0x00010041;//Ribbon out (41)

	//3. 进卡
	dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_MOVE_CARD_TO_PREPARE);
	GetErrorString(dwRet, szError);
	printf("SOY_PR_ExecCommandA(CMD_MOVE_CARD_TO_PREPARE) return = %d (%s)\n", dwRet, szError);
	if ( dwRet != 0 )
		return dwRet;

	//4. 判断打印机内是否有卡
	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_CARD_POSITION, szCardPos);
	printf("SOY_PR_GetPrinterInfoA(INFO_CARD_POSITION) => %s\n", szCardPos);
	nCardPos = atoi(szCardPos);
	if ( nCardPos == 0 )//打印机内无卡，流程结束
		return 0x0001005F;//Card out

	//5. 打印
	dwRet = TestPrint(szPrinterPort, 1);

	//6. 打印完不排卡时，从前门将卡片排出
	if ( dwRet == 0 && nType == 2 )
	{
		usleep(5000*1000);//等 5 秒
		dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_MOVE_CARD_TO_FRONT);
		GetErrorString(dwRet, szError);
		printf("SOY_PR_ExecCommandA(CMD_MOVE_CARD_TO_FRONT) return = %d (%s)\n", dwRet, szError);
	}

	return dwRet;
}

int setS20N(char* szPrinterPort, int nType)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};
	(void)szError;
	SOY_PR_SetLogLevel(1);

	//check printer model
	char				szModel[32] = {0};

	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
	printf("SOY_PR_GetPrinterInfoA(INFO_MODEL_NAME) return = %d, model name = \"%s\"\n", dwRet, szModel);
	if ( dwRet == 0 )
	{
		if ( strcmp(szModel, "S20N") != 0 )
			dwRet = 1200;//The specified device name is invalid.
	}

	if ( dwRet != 0 )
	{
		return dwRet;
	}

	int32_t		nInputBin = 0;
	bool		bAutoFeedM = false;
	bool		bAdfHookMode = false, bRetryHookMode = false, bCardOutSensor = false;
	int32_t		nOutputBin = 0;
	bool		bWaitForRemoval = false;
	int32_t		nRejectBin = 0;

	uint8_t		byWaitPos = 0;
	uint32_t	dwWaitTime = 0;

	if ( nType == 1 )
	{
		nInputBin = 1;//后端手动进卡口
		bAutoFeedM = true;//侦测到卡片时立即自动进卡
		nOutputBin = CONFIG_MANUAL_FEED_FRONT;//前端手动进卡口
		bWaitForRemoval = true;//打印完成后走到待取卡位置
		dwRet = SetCardInOut(szPrinterPort, nInputBin, bAutoFeedM, bAdfHookMode, bRetryHookMode, bCardOutSensor, nOutputBin, bWaitForRemoval, nRejectBin);

		byWaitPos = 60;//x1mm
		dwWaitTime = 0;//x0.5second
		dwRet = SetStandbyParam(szPrinterPort, nOutputBin, byWaitPos, dwWaitTime);
	}
	else if ( nType == 2 )
	{
		nInputBin = 2;//后端手动进卡口
		bAutoFeedM = true;//侦测到卡片时立即自动进卡
		nOutputBin = 1;//前端出卡
		dwRet = SetCardInOut(szPrinterPort, nInputBin, bAutoFeedM, bAdfHookMode, bRetryHookMode, bCardOutSensor, nOutputBin, bWaitForRemoval, nRejectBin);
	}

	return dwRet;
}

//=============================================================================
uint32_t printS22MB(char* szPrinterPort, bool b300x600, int nHeatFrontK)
{
	uint32_t			dwRet = 0;
	char				szError[256] = {0};
	bool				bCancelJob = false;

	uint32_t			dwStatus = 0;

	char				szCardPos[32] = {0};
	int					nCardPos = 0;
	int					nCommand = 0;

	char				szRibbonType[32] = {0};
	char				szRibbonCount[32] = {0};
	int					nRibbonCount = 0;

	char				szFwVer[32] = {0};

	(void)szRibbonType;
	(void)bCancelJob;
	(void)nCommand;
	(void)szRibbonType;

	SOY_PR_SetLogLevel(1);

	//1. 获取打印机状态
	dwStatus = 170;//device is busy
	while ( dwStatus == 170 )
	{
		dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
		GetErrorString(dwStatus, szError);
		printf("SOY_PR_GetPrinterStatusA() return = %d, dwStatus = 0x%08X (%s)\n", dwRet, dwStatus, szError);
		if ( dwRet != 0 )
			dwStatus = dwRet;

		if ( dwStatus == 170 )
			usleep(500*1000);
	}

	//1.a 打印机未连接，流程结束
	if ( dwStatus == 1167 )//The device is not connected.
		return 1167;

	//1.b 打印机未就绪
	if ( dwStatus != 0 )
	{
		//判断打印机内是否有卡
		dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_CARD_POSITION, szCardPos);
		printf("SOY_PR_GetPrinterInfoA(INFO_CARD_POSITION) => %s\n", szCardPos);
		nCardPos = atoi(szCardPos);
		if ( nCardPos != 0 )//打印机内有卡，将卡片排出
		{
			dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_MOVE_CARD_TO_HOPPER);
			GetErrorString(dwRet, szError);
			printf("SOY_PR_ExecCommandA(CMD_MOVE_CARD_TO_HOPPER) return = %d (%s)\n", dwRet, szError);
			//if ( dwRet != 0 )
			//	return dwRet;
		}

		//复位
		dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_RESET_PRINTER_HARD);
		GetErrorString(dwRet, szError);
		printf("SOY_PR_ExecCommandA(CMD_RESET_PRINTER_HARD) return = %d (%s)\n", dwRet, szError);
		if ( dwRet != 0 )
			return dwRet;

		dwStatus = 170;//device is busy
		while ( dwStatus == 170 )
		{
			dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
			GetErrorString(dwStatus, szError);
			printf("SOY_PR_GetPrinterStatusA() return = %d, dwStatus = 0x%08X (%s)\n", dwRet, dwStatus, szError);
			if ( dwRet != 0 )
				dwStatus = dwRet;

			if ( dwStatus == 170 )
				usleep(500*1000);
		}

		//打印机未就绪，流程结束
		dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
		GetErrorString(dwStatus, szError);
		printf("SOY_PR_GetPrinterStatusA() return = %d, dwStatus = 0x%08X (%s)\n", dwRet, dwStatus, szError);
		if ( dwRet != 0 )
			return dwRet;

		if ( dwStatus != 0 )
			return dwStatus;
	}

	//2. 判断色带是否足量
	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_RIBBON_COUNT, szRibbonCount);
	printf("SOY_PR_GetPrinterInfoA(INFO_RIBBON_COUNT) => %s\n", szRibbonCount);
	nRibbonCount = atoi(szRibbonCount);

	//2.a 色带不足量，流程结束
	if ( nRibbonCount < 1 )
		return 0x00010041;//Ribbon out (41)

	//3. 读取固件版本
	dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_FW_VERSION, szFwVer);
	printf("SOY_PR_GetPrinterInfoA(INFO_FW_VERSION) => %s\n", szFwVer);

	//-----------------------------------------------------
	//4. 打印
	dwRet = TestPrint(szPrinterPort, 1);

	//5. 打印完不排卡时，从前门将卡片排出
	if ( dwRet == 0 )
	{
		usleep(5000*1000);//等 5 秒
		dwRet = SOY_PR_ExecCommandA(szPrinterPort, CMD_MOVE_CARD_TO_FRONT);
		GetErrorString(dwRet, szError);
		printf("SOY_PR_ExecCommandA(CMD_MOVE_CARD_TO_FRONT) return = %d (%s)\n", dwRet, szError);
	}

	return dwRet;
}

//=============================================================================
int32_t	main(int32_t argc, char *argv[])
{
	uint32_t			dwRet = 0;
	char				szPrinterPort[128] = {0};

	char				szSdkVersion[32] = {0};
	char				szModel[32] = {0};
	char				szFwVersion[32] = {0};
	char				szSerial[32] = {0};
	char				szRibbonType[32] = {0};
	char				szRibbonCount[32] = {0};
	char				szPrintCount[32] = {0};
	char				szRegionCode[32] = {0};
	char				szUncleanCount[32] = {0};
	char				szModuleValue[32] = {0};
	char				szCardPos[32] = {0};
	char				szRejectBoxStatus[32] = {0};
	int					nInfoValue = 0;

	uint32_t			dwStatus = 0;
	char				szError[256] = {0};

	bool				bVersion = false,
						bInfo = false,
						bCommand = false,
						bStatus = false,
						bPrint = false,
						bMagRead = false,
						bMagEncodeLoCo = false,
						bMagEncodeHiCo = false;
	char				szCmd[16] = {0};
	int32_t				nCommand = 0;
	int32_t				nPrintSide = 1;
	int32_t				nSetS20 = 0,
						nPrintS20 = 0;
	int32_t             nSetS20N = 0;
	//
	bool				bSetS20R = false,
						bPrintS20R = false,
						bSetS21 = false,
						bPrintS21 = false,
						bSetS22J = false,
						bPrintS22J = false,
						bPrintS22MB = false;

	//20220307
	bool				b300x600dpi = false;
	int32_t				nHeatFrontK = 0;

	if ( argc == 1 || strcmp(argv[1], "--help") == 0 )
	{
		printf("Usage: SeaoryDemo [options]\n");
		printf("Options:\n");
		printf("  --help               Display this information\n\n");
		printf("  -version             Display SeaorySDK version number\n");
		printf("  -port=<printer>      Set the printer path or IP address.\n \
                      Such as \"/dev/usb/lp0\" or \"192.168.0.21\".\n \
                      Default is \"/dev/usb/lp0\".\n");
		printf("  -info                List printer information.\n");
		printf("  -status              Get current printer status.\n");
		printf("  -print=<side>        Print one sample card. side=1\n");
		printf("    <side> can be one of following:\n");
		printf("    1                  Print front side.\n");
		printf("    2                  Print back side.\n");
		printf("    3                  Print both sides.\n");
		printf("  -mag-read            Read magnetic stripe card track data.\n");
		printf("  -mag-encode          Encode magnetic stripe card track data.\n");
		printf("  -simple-print        Demo usage of simple print functions.\n\n");

		printf("  -set-S20R            Set card in/out options for S20R.\n");
		printf("  -print-S20R          Demo usage of S20R printing.\n");
		printf("  -set-S21             Set card in/out options for S21.\n");
		printf("  -print-S1            Demo usage of S21 printing.\n");
		printf("  -set-S22J            Set card in/out options for S22J.\n");
		printf("  -print-S22J          Demo usage of S22J printing.\n\n");
		printf("  -set-S20N-1           Set card in/out options for S20N type 1.\n");
		printf("  -set-S20N-2           Set card in/out options for S20N type 2.\n");
		printf("  -set-S20-1           Set card in/out options for S20 type 1.\n");
		printf("  -set-S20-2           Set card in/out options for S20 type 2.\n");
		printf("  -print-S20-1         Demo usage of S20 printing with type 1 setting.\n");
		printf("  -print-S20-2         Demo usage of S20 printing with type 2 setting.\n\n");

		printf("  -command=<cmd>       Execute printer command.\n");
		printf("    <cmd> can be one of following:\n");
		printf("    Move2Hopper        Move Card to Output Hopper.\n");
		printf("    Move2Contact       Move Card to Contact Encoder Station.\n");
		printf("    Move2Contactless   Move Card to Contactless Hopper.\n");
		printf("    Move2StandbyBack   Move Card to Standby (back).\n");
		printf("    Move2Flipper       Move Card to Flipper.\n");
		printf("    Move2RejectFront   Move Card to Reject Box (front).\n");
		printf("    Move2RejectDown    Move Card to Reject Box (down).\n");
		printf("    Move2StandbyFront  Move Card to Standby (front).\n");
		printf("    Move2Front         Move Card to Front position.\n");
		printf("    Move2Prepare       Move Card to Prepare position.\n");

		printf("    Reset              Hard reset printer.\n");
		printf("    ResetJam           Card jam reset.\n");
		printf("    Clean              Clean card path.\n");
		printf("    FlipCard           Flip card then move card to prepare position.\n");
		printf("    CleanNoEject       Clean card path, after finished, do not eject card.\n");
		printf("    EraseFullCard      Erase rewritable card whole card.\n");

		return 0;
	}

	//printf("argc = %d\n", argc);
	for(int32_t i=1;i<argc;i++)
	{
		if ( strstr(argv[i], "-version") )
			bVersion = true;
		else if ( strstr(argv[i], "-port=") )
			strcpy(szPrinterPort, argv[i]+6);
		else if ( strcmp(argv[i], "-info") == 0 )
			bInfo = true;
		else if ( strcmp(argv[i], "-status") == 0 )
			bStatus = true;
		else if ( strstr(argv[i], "-print=") )
		{
			bPrint = true;
			strcpy(szCmd, argv[i]+7);

			if ( strcmp(szCmd, "1") == 0 )
				nPrintSide = 1;
			else if ( strcmp(szCmd, "2") == 0 )
				nPrintSide = 2;
			else if ( strcmp(szCmd, "3") == 0 )
				nPrintSide = 3;
		}
		else if ( strcmp(argv[i], "-mag-read") == 0 )
			bMagRead = true;
		else if ( strcmp(argv[i], "-mag-encode-loco") == 0 )
			bMagEncodeLoCo = true;
		else if ( strcmp(argv[i], "-mag-encode-hico") == 0 )
			bMagEncodeHiCo = true;
		else if ( strcmp(argv[i], "-set-S20R") == 0 )
			bSetS20R = true;
		else if ( strcmp(argv[i], "-print-S20R") == 0 )
			bPrintS20R = true;
		else if ( strcmp(argv[i], "-set-S21") == 0 )
			bSetS21 = true;
		else if ( strcmp(argv[i], "-print-S21") == 0 )
			bPrintS21 = true;
		else if ( strcmp(argv[i], "-set-S22J") == 0 )
			bSetS22J = true;
		else if ( strcmp(argv[i], "-print-S22J") == 0 )
			bPrintS22J = true;
		else if ( strcmp(argv[i], "-print-S22MB") == 0 )
			bPrintS22MB = true;
		else if ( strcmp(argv[i], "-300x600") == 0 )
			b300x600dpi = true;
		else if ( strstr(argv[i], "-heat-front-k=") )
		{
			nHeatFrontK = atoi(argv[i]+strlen("-heat-front-k="));
printf("  argv[i] => %s\n", argv[i]);
printf("    => %s\n", argv[i]+strlen("-heat-front-k="));
printf("  nHeatFrontK = %d\n", nHeatFrontK);

		}
		else if ( strcmp(argv[i], "-set-S20-1") == 0 )
			nSetS20 = 1;
		else if ( strcmp(argv[i], "-set-S20-2") == 0 )
			nSetS20 = 2;
		else if ( strcmp(argv[i], "-print-S20-1") == 0 )
			nPrintS20 = 1;
		else if ( strcmp(argv[i], "-print-S20-2") == 0 )
			nPrintS20 = 2;
		else if ( strcmp(argv[i], "-set-S20N-1") == 0 )
			nSetS20N = 1;
		else if ( strcmp(argv[i], "-set-S20N-2") == 0 )
			nSetS20N = 2;

		else if ( strstr(argv[i], "-command=") )
		{
			bCommand = true;
			strcpy(szCmd, argv[i]+9);

			if ( strcmp(szCmd, "Move2Hopper") == 0 )
				nCommand = CMD_MOVE_CARD_TO_HOPPER;
			else if ( strcmp(szCmd, "Move2Contact") == 0 )
				nCommand = CMD_MOVE_CARD_TO_CONTACT;
			else if ( strcmp(szCmd, "Move2Contactless") == 0 )
				nCommand = CMD_MOVE_CARD_TO_CONTACTLESS;
			else if ( strcmp(szCmd, "Move2StandbyBack") == 0 )
				nCommand = CMD_MOVE_CARD_TO_STANDBY_BACK;
			else if ( strcmp(szCmd, "Move2Flipper") == 0 )
				nCommand = CMD_MOVE_CARD_TO_FLIPPER;
			else if ( strcmp(szCmd, "Move2RejectFront") == 0 )
				nCommand = CMD_MOVE_CARD_TO_REJECT_BOX_FRONT;
			else if ( strcmp(szCmd, "Move2RejectDown") == 0 )
				nCommand = CMD_MOVE_CARD_TO_REJECT_BOX_DOWN;
			else if ( strcmp(szCmd, "Move2StandbyFront") == 0 )
				nCommand = CMD_MOVE_CARD_TO_STANDBY_FRONT;
			else if ( strcmp(szCmd, "Move2Front") == 0 )
				nCommand = CMD_MOVE_CARD_TO_FRONT;
			else if ( strcmp(szCmd, "Move2Prepare") == 0 )
				nCommand = CMD_MOVE_CARD_TO_PREPARE;

			else if ( strcmp(szCmd, "Reset") == 0 )
				nCommand = CMD_RESET_PRINTER_HARD;
			else if ( strcmp(szCmd, "ResetJam") == 0 )
				nCommand = CMD_RESET_PRINTER_JAM;
			else if ( strcmp(szCmd, "Clean") == 0 )
				nCommand = CMD_CLEAN_CARD_PATH;
			else if ( strcmp(szCmd, "FlipCard") == 0 )
				nCommand = CMD_FLIP_CARD;
			else if ( strcmp(szCmd, "CleanNoEject") == 0 )
				nCommand = CMD_CLEAN_CARD_PATH_NO_EJECT;
			else if ( strcmp(szCmd, "EraseFullCard") == 0 )
				nCommand = CMD_ERASE_FULL_CARD;
		}
	}

	if ( bVersion )
	{
		dwRet = SOY_PR_SdkVersionA(szSdkVersion);
		printf("SDK version = %s\n", szSdkVersion);
		return 0;
	}

	if ( szPrinterPort[0] == 0 )
	{
		// libusb_device **devs;
		// libusb_device_descriptor desc;

		// int cnt;

		// int ret = libusb_init(NULL);
		// if (ret < 0) {
		// 	printf("failed to init libusb,%s",libusb_strerror(ret));
		// 	return 0;
		// }

		// cnt = libusb_get_device_list(NULL,&devs);
		// if (cnt < 0) {
		// 	printf("get devices list failed,%s",libusb_strerror(cnt));
		// 	return 0;
		// }

		// for (int i = 0; i < cnt;i++) {
		// 	int ret = libusb_get_device_descriptor(devs[i],&desc);
		// 	if (ret < 0) {
		// 		printf("get device descriptor failed");
		// 		return 0;
		// 	}
		// 	if (desc.idVendor == 12253) {
		// 		printf("found !");break;
		// 	}
		// }
		//printf("-port is not set.\n");
		//return 0;
		strcpy(szPrinterPort, "/dev/usb/lp0");
	}

	if ( bInfo )
	{
		dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_MODEL_NAME, szModel);
		if ( dwRet != 0 )
		{
			GetErrorString(dwRet, szError);
			printf("SOY_PR_GetPrinterInfoA() return = %d (%s)\n", dwRet, szError);
		}
		else
		{
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_FW_VERSION,        szFwVersion);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_SERIAL_NUMBER,     szSerial);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_RIBBON_TYPE,       szRibbonType);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_RIBBON_COUNT,      szRibbonCount);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_PRINT_COUNT,       szPrintCount);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_REGION_CODE,       szRegionCode);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_UNCLEAN_COUNT,     szUncleanCount);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_INSTALLED_MODULE,  szModuleValue);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_CARD_POSITION,     szCardPos);
			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_REJECT_BOX_STATUS, szRejectBoxStatus);

			printf("Model            = %s\n", szModel);
			printf("Firmware Version = %s\n", szFwVersion);
			printf("Serial Number    = %s\n", szSerial);
			printf("Ribbon Type      = %s\n", szRibbonType);
			printf("Ribbon Count     = %s\n", szRibbonCount);
			printf("Print Count      = %s\n", szPrintCount);
			printf("Region Code      = %s\n", szRegionCode);
			printf("Unclean Count    = %s\n", szUncleanCount);

			nInfoValue = atoi(szCardPos);
			switch(nInfoValue)
			{
				case 0:		strcpy(szCardPos, "Out of printer");	break;
				case 3:		strcpy(szCardPos, "Front standby");		break;
				case 4:		strcpy(szCardPos, "Flipper");			break;
				case 5:		strcpy(szCardPos, "Mag in");			break;
				case 6:		strcpy(szCardPos, "Mag out");			break;
				case 7:		strcpy(szCardPos, "Start printing");	break;
				case 8:		strcpy(szCardPos, "Print end");			break;
				case 9:		strcpy(szCardPos, "Contact");			break;
				case 10:	strcpy(szCardPos, "Contactless");		break;
				case 11:	strcpy(szCardPos, "Back standby");		break;
				case 12:	strcpy(szCardPos, "Card jam pos");		break;
				case 13:	strcpy(szCardPos, "Prepare pos");		break;
				case 15:	strcpy(szCardPos, "Unknow pos");		break;
			}
			printf("Card Position    = %d (%s)\n", nInfoValue, szCardPos);

			nInfoValue = atoi(szModuleValue);

			printf("Installed Module::\n");
			printf("  Flipper             => %s\n", (nInfoValue & 1)   ?"Yes":"NO");
			printf("  Magnetic Stripe     => %s\n", (nInfoValue & 2)?"Yes":"NO");
			printf("  Contact Encoder     => %s\n", (nInfoValue & 4)?"Yes":"NO");
			printf("  Contactless Encoder => %s\n", (nInfoValue & 8)      ?"Yes":"NO");
			printf("  Ethernet            => %s\n", (nInfoValue & 16)  ?"Yes":"NO");
			printf("  600 DPI             => %s\n", (nInfoValue & 65536)    ?"Yes":"NO");

			dwRet = SOY_PR_GetPrinterInfoA(szPrinterPort, INFO_REJECT_BOX_STATUS, szRejectBoxStatus);

			if ( dwRet == 50 )//ERROR_NOT_SUPPORTED
				printf("Front reject box status => Not supported.\n");
			else if ( dwRet == 0 )
			{
				nInfoValue = atoi(szRejectBoxStatus);
				printf("Front reject box status::\n");
				printf("  Reject box cover open => %s\n", (nInfoValue&0x00000001)?"Yes":"NO");
				printf("  Reject box full       => %s\n", (nInfoValue&0x00000002)?"Yes":"NO");
			}
		}
	}

	if ( bStatus )
	{
		strcpy(szError, "Ready");
		dwRet = SOY_PR_GetPrinterStatusA(szPrinterPort, &dwStatus);
		if ( dwRet != 0 )
			dwStatus = dwRet;

		if ( dwStatus != 0 )
			GetErrorString(dwStatus, szError);
		printf("Printer Status = %d (%s)\n", dwStatus, szError);
	}

	if ( bCommand )
	{
		strcpy(szError, "Ready");
		dwRet = SOY_PR_ExecCommandA(szPrinterPort, nCommand);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("Execute command return = %d (%s)\n", dwRet, szError);
	}

	if ( bMagEncodeLoCo )
	{
		strcpy(szError, "Ready");
		dwRet = TestEncodeMagTrackData(szPrinterPort, 0);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("TestEncodeMagTrackData() return = %d (%s)\n", dwRet, szError);
	}

	if ( bMagEncodeHiCo )
	{
		strcpy(szError, "Ready");
		dwRet = TestEncodeMagTrackData(szPrinterPort, 1);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("TestEncodeMagTrackData() return = %d (%s)\n", dwRet, szError);
	}

	if ( bMagRead )
	{
		strcpy(szError, "Ready");
		dwRet = TestReadMagTrackData(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("TestReadMagTrackData() return = %d (%s)\n", dwRet, szError);
	}

	if ( bPrint )
	{
		strcpy(szError, "Ready");
		dwRet = TestPrint(szPrinterPort, nPrintSide);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("TestPrint() return = %d (%s)\n", dwRet, szError);
	}

	//
	if ( bSetS20R )
	{
		strcpy(szError, "Ready");
		dwRet = setS20R(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("setS20R() return = %d (%s)\n", dwRet, szError);
	}

	if ( bPrintS20R )
	{
		strcpy(szError, "Ready");
		dwRet = printS20R(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("printS20R() return = %d (%s)\n", dwRet, szError);
	}

	if ( bSetS21 )
	{
		strcpy(szError, "Ready");
		dwRet = setS21(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("setS21() return = %d (%s)\n", dwRet, szError);
	}

	if ( bPrintS21 )
	{
		strcpy(szError, "Ready");
		dwRet = printS21(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("printS21() return = %d (%s)\n", dwRet, szError);
	}

	if ( bSetS22J )
	{
		strcpy(szError, "Ready");
		dwRet = setS22J(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("setS22J() return = %d (%s)\n", dwRet, szError);
	}

	if ( bPrintS22J )
	{
		strcpy(szError, "Ready");
		dwRet = printS22J(szPrinterPort);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("printS22J() return = %d (%s)\n", dwRet, szError);
	}

	if ( bPrintS22MB )
	{
		strcpy(szError, "Ready");
		dwRet = printS22MB(szPrinterPort, b300x600dpi, nHeatFrontK);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("printS22MB() return = %d (%s)\n", dwRet, szError);
	}

	if ( nSetS20 > 0 )
	{
		strcpy(szError, "Ready");
		dwRet = setS20(szPrinterPort, nSetS20);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("setS20() return = %d (%s)\n", dwRet, szError);
	}

	if ( nPrintS20 > 0 )
	{
		strcpy(szError, "Ready");
		dwRet = printS20(szPrinterPort, nPrintS20);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("printS20() return = %d (%s)\n", dwRet, szError);
	}

	if ( nSetS20N > 0 )
	{
		strcpy(szError, "Ready");
		dwRet = setS20N(szPrinterPort, nSetS20N);
		if ( dwRet != 0 )
			GetErrorString(dwRet, szError);
		printf("setS20N() return = %d (%s)\n", dwRet, szError);
	}

	return 0;
}
